#ifndef CUDA_EPI_MODEL_H
#define CUDA_EPI_MODEL_H

#include "../epimodel.h"
#include "../epimodelparameters.h"
#include "CudaRand.h"
#include <thrust/device_vector.h>

__device__ inline void Barrier(int* mutex, int target_value){
	int tid_in_block = threadIdx.x * blockDim.y + threadIdx.y;
	
	if(tid_in_block == 0){
		atomicAdd(&(mutex[0]),1);
		while(mutex[0] != target_value){}
	}
	__syncthreads();
};

__device__ inline void EnterCS(int* mutex){
        do{}while(atomicCAS(&(mutex[0]),0,1));
		printf("(%d,%d) with size  %d inside CS \n",threadIdx.x,blockIdx.x,gridDim.x);

};

__device__ inline void QuitCS(int* mutex){
        __threadfence();
		mutex[0] = 0;
};

template <class T>
__device__ inline T dmin(T a, T b){
	return (a<b)?a:b;
};

void cudaInitialize(EpiModel& input_model);
void copyPerson(bool host_to_device);
void copyCommunity(bool host_to_device);
void copyTract(bool host_to_device);
bool compareModel(EpiModel& compare_model); // compare if two models are the same (cuda and flute)
void clean();

struct dPerson {
	bool valid;   // cuda special, not in original defination
	bool bWantAV;
	bool bWantVac;
	unsigned int id;
 	unsigned char age;	// age group
	unsigned char status;	// infection status
	unsigned char nWhichVload;	// which viral load trajectory (vload) to use?
	unsigned char vday;   // vaccination timer (number of days elapsed)
	char iday;	// infected days	
	unsigned char ibits;  // state info for infection
  	unsigned char vbits;  // state info for vaccine
	double pri;	// infectiousness multiplier
	double prs;	// susceptibility multiplier
	double fBaselineVES;	// baseline VES before vaccination
	unsigned int nDayComm; // ID of daytime (work,school) community
	char nTravelTimer;	// travel time left
	int nWorkplace;	// work or school group
	unsigned int nDayTract;	// ID of daytime (work, school) tract
	int family; // family ID
	int sourceid; // keeping track of the source of infection
	char sourcetype; // in which setting infection took place
	int nInfectedTime;
	unsigned int nHomeComm;
	char nDayNeighborhood;
	unsigned char householdcluster;// household cluster
	char nHomeNeighborhood;    // neighborhood (0-3)
	char nAVTimer;        // antiviral timer (number of tablets left)
	unsigned char nQuarantineTimer;
	unsigned char nVaccinePriority;
	unsigned int nVaccineRestrictionBits;
	bool bVaccineEligible[NUMVACCINES];
	
	dPerson(){valid = true;}	
	
	dPerson(Person& p){
		valid = true;
		bWantAV = p.bWantAV;
		bWantVac = p.bWantVac;
		id = p.id;
        age = p.age;
        status = p.status;
        nWhichVload = p.nWhichVload;
        vday = p.vday;
        iday = p.iday;
        ibits = p.ibits;
        vbits = p.vbits;
        pri = p.pri;
        prs = p.prs;
        fBaselineVES = p.fBaselineVES;
		nDayComm = p.nDayComm;
		nTravelTimer = p.nTravelTimer;
		nWorkplace = p.nWorkplace;
		nDayTract = p.nDayTract;
		family = p.family;
		sourceid = p.sourceid;
		sourcetype = p.sourcetype;
		nInfectedTime = p.nInfectedTime;
		nHomeComm = p.nHomeComm;
		nDayNeighborhood = p.nDayNeighborhood;
		householdcluster = p.householdcluster;
		nHomeNeighborhood = p.nHomeNeighborhood;
		nQuarantineTimer = p.nQuarantineTimer;
		nAVTimer = p.nAVTimer;
		nVaccinePriority = p.nVaccinePriority;
		nVaccineRestrictionBits = p.nVaccineRestrictionBits;
		for(int i = 0; i < NUMVACCINES; i++) bVaccineEligible[i] = p.bVaccineEligible[i];
	}
	
	void copyToPerson(Person& p){
		p.id = id;
		p.bWantAV = bWantAV;
        p.age = age;
        p.status = status;
        p.nWhichVload = nWhichVload;
        p.vday = vday;
        p.iday = iday;
        p.ibits = ibits;
        p.vbits = vbits;
        p.pri = pri;
        p.prs = prs;
        p.fBaselineVES = fBaselineVES;
		p.nDayComm = nDayComm;
		p.nTravelTimer = nTravelTimer;
		p.nWorkplace = nWorkplace;
		p.nDayTract = nDayTract;
		p.family = family;
		p.sourceid = sourceid;
		p.sourcetype = sourcetype;
		p.nInfectedTime = nInfectedTime;
		p.nHomeComm = nHomeComm;
		p.nDayNeighborhood = nDayNeighborhood;
		p.householdcluster = householdcluster;
		p.nHomeNeighborhood = nHomeNeighborhood;
		p.nQuarantineTimer = nQuarantineTimer;
		p.nAVTimer = nAVTimer;
		p.nVaccinePriority = nVaccinePriority;
		p.bWantVac = bWantVac;
		p.nVaccineRestrictionBits = nVaccineRestrictionBits;
		for(int i = 0; i < NUMVACCINES; i++) p.bVaccineEligible[i] = bVaccineEligible[i];
	}
	
	__device__ static bool isInfected(const dPerson &p) { return p.status&INFECTED; }
	__device__ static bool isInfectious(const dPerson &p) { return (p.status&INFECTED && p.iday>=0); }
	__device__ static bool isVaccinated(const dPerson &p) { return p.status&VACCINATED; }
	__device__ static bool needsBoost(const dPerson &p) { return p.status&NEEDSBOOST; }
	__device__ static unsigned char whichVaccine(const dPerson &p) { return p.vbits&0x0F; }
	__device__ static bool isAntiviral(const dPerson &p) { return p.status&ANTIVIRAL; }
	__device__ static bool isSymptomatic(const dPerson &p) { return p.status&SYMPTOMATIC; }
	__device__ static bool isWithdrawn(const dPerson &p) { return p.vbits&WITHDRAWN; }
	__device__ static bool isQuarantined(const dPerson &p) { return p.vbits&QUARANTINED; }
	__device__ static bool isChild(const dPerson &p) { return (p.age<=1); } // is a child?
	__device__ static bool isBoosted(const dPerson &p) { return p.status&BOOSTED; }
	__device__ static bool isAVProphylaxis(const dPerson &p) { return p.vbits&AVPROPHYLAXIS; }
	__device__ static bool isWorkingAge(const dPerson &p) { return (p.age==2 || p.age==3); } 
	__device__ static bool isEssential(const dPerson &p) { return p.nVaccineRestrictionBits&VESSENTIAL; }
	__device__ static bool isHighRisk(const dPerson &p) { return p.nVaccineRestrictionBits&VHIGHRISK; }
	__device__ static bool isSusceptible(const dPerson &p) { return p.status&SUSCEPTIBLE; }
	__device__ static void clearSusceptible(dPerson &p) {p.status&=~SUSCEPTIBLE;}
	__device__ static void setWillBeSymptomatic(dPerson &p) {p.ibits|=WILLBESYMPTOMATIC; }
	__device__ static void setNeedsBoost(dPerson &p) {p.status|=NEEDSBOOST;}
	__device__ static void setWillBeAscertained(dPerson &p) {p.ibits|=WILLBEASCERTAINED; }
	__device__ static void setIncubationDays(dPerson &p, unsigned int x) {p.ibits=(p.ibits&0xF8u)|x; }
	__device__ static void setWithdrawDays(dPerson &p, unsigned int x) {p.ibits=(p.ibits&0xC7u)|(x<<3); } 
	__device__ static unsigned int getWithdrawDays(const dPerson &p) { return (p.ibits>>3)&0x7u; }
	__device__ static void setInfected(dPerson &p) {p.status|=INFECTED;}
	__device__ static int getIncubationDays(const dPerson &p) { return p.ibits&0x7u; }
	__device__ static bool getWillBeSymptomatic(const dPerson &p) { return p.ibits&WILLBESYMPTOMATIC; }
	__device__ static void setSymptomatic(dPerson &p) {p.status|=SYMPTOMATIC;}
	__device__ static bool getWillBeAscertained(const dPerson &p) { return p.ibits&WILLBEASCERTAINED; }
	__device__ static void setWithdrawn(dPerson &p) {p.vbits|=WITHDRAWN;}
	__device__ static void clearQuarantined(dPerson &p) {p.vbits&=(~QUARANTINED);}
	__device__ static void setQuarantined(dPerson &p) {p.vbits|=QUARANTINED;}
	__device__ static void clearAntiviral(dPerson &p) {p.status&=(~ANTIVIRAL);}
	__device__ static void clearAVProphylaxis(dPerson &p) {p.vbits&=~AVPROPHYLAXIS; }
	__device__ static void setAVProphylaxis(dPerson &p) {p.vbits|=AVPROPHYLAXIS;}
	__device__ static bool isPregnant(const dPerson &p) { return p.nVaccineRestrictionBits&VPREGNANT; }
	__device__ static bool isInfant(const dPerson &p) { return p.nVaccineRestrictionBits&VINFANT; }
	__device__ static void clearNeedsBoost(dPerson &p) {p.status|=NEEDSBOOST;}
	__device__ static void setWhichVaccine(dPerson &p, unsigned char nWhich) {p.vbits|=nWhich; }
	__device__ static unsigned char getVaccinePriority(dPerson &p) { return p.nVaccinePriority; }
	__device__ static void setVaccinated(dPerson &p) {p.status|=VACCINATED;}
	__device__ static void setBoosted(dPerson &p) {p.status|=BOOSTED;}
	__device__ static void setAntiviral(dPerson &p) {p.status|=ANTIVIRAL;}
	
};

struct dCommunity{
	unsigned int id;	
	int nTractID;
	unsigned int nFirstPerson,nLastPerson;	
	int nNumWorkGroups;
	double daycpcm[5];
	double daycpnh[5];
	double cpcm[5];        // community-specific community contact rates
	double cpnh[5];        // community-specific neighborhood contact rates
	double cps[10];
	int ninf[TAG];
	int nEverInfected[TAG];
	int nsym[TAG];
	int nEverSymptomatic[TAG];
	int nEverAscertained[TAG]; // number of residents ever ascertained
	
	dCommunity(){}
	
	void copyToCommunity(Community& comm){
		comm.id = id;
		comm.nTractID = nTractID;
		comm.nFirstPerson = nFirstPerson;
		comm.nLastPerson = nLastPerson;
		comm.nNumWorkGroups = nNumWorkGroups;
		for(int i = 0; i < 5; i++){
			comm.daycpcm[i] = daycpcm[i];
			comm.daycpnh[i]=daycpnh[i];
			comm.cpcm[i] = cpcm[i];
			comm.cpnh[i] = cpnh[i];
		}
		for(int i = 0; i < 10; i++){comm.cps[i] = cps[i];}	
		for(int i = 0; i < TAG; i++){
			comm.ninf[i] = ninf[i];
			comm.nEverInfected[i] = nEverInfected[i];
			comm.nsym[i]=nsym[i];
			comm.nEverSymptomatic[i] = nEverSymptomatic[i];
			comm.nEverAscertained[i] = nEverAscertained[i];
		}
	}
	
	dCommunity(Community& comm){
		id = comm.id;
		nTractID = comm.nTractID;
		nFirstPerson = comm.nFirstPerson;
		nLastPerson = comm.nLastPerson;
		nNumWorkGroups = comm.nNumWorkGroups;
		for(int i = 0; i < 5; i++){
			daycpcm[i] = comm.daycpcm[i];
			daycpnh[i]= comm.daycpnh[i];
			cpcm[i] = comm.cpcm[i];
			cpnh[i] = comm.cpnh[i];
		}
		for(int i = 0; i < 10; i++){cps[i] = comm.cps[i];}
		for(int i = 0; i < TAG; i++){
			ninf[i] = comm.ninf[i];
			nEverInfected[i] = comm.nEverInfected[i];
			nsym[i]=comm.nsym[i];
			nEverSymptomatic[i] = comm.nEverSymptomatic[i];
			nEverAscertained[i] = comm.nEverAscertained[i];
		}
	}
};
const static int dTARGETCOMMUNITYSIZE = 2000;
const static int dFAMILIESPERCLUSTER = 4;
const static int dWORKGROUPSIZE = 20;

struct dCommWorker{
	unsigned int comm_id; // its correspoding coummunity id
	unsigned int worker_id; // id of the person who is working with community (non-resident)

	dCommWorker(){}

	dCommWorker(unsigned int _comm_id, unsigned int _worker_id){
		comm_id = _comm_id; worker_id = _worker_id;		
	}
	__device__
	bool operator<(const dCommWorker other) const{
		return comm_id < other.comm_id;
	}
};

struct dCommVisitor{
	unsigned int comm_id; // its correspoding coummunity id
	dPerson visitor; // id of the person who is visiting this community
	
	dCommVisitor(){}
	
	dCommVisitor(unsigned int _comm_id, dPerson _visitor){
		comm_id = _comm_id; visitor = _visitor;
	}
	
	__device__
	bool operator<(const dCommVisitor other) const{
		return comm_id < other.comm_id;
	}
};

struct dTract{
	unsigned int status;
	unsigned int nFirstCommunity;
	unsigned int nLastCommunity;
	unsigned int fips_state;
	int nSchoolClosureTimer;
	bool bSchoolClosed[9];

	dTract(){}

	dTract(Tract& t){
		status = t.status;
		nFirstCommunity = t.nFirstCommunity;
		nLastCommunity = t.nLastCommunity;
		fips_state = t.fips_state;
		nSchoolClosureTimer = t.nSchoolClosureTimer;
		for(int i = 0; i < 9; i++) bSchoolClosed[i] = t.bSchoolClosed[i];
	}

	void copyToTract(Tract& t){
		t.status = status;
		t.nFirstCommunity = nFirstCommunity;
		t.nLastCommunity = nLastCommunity;
		t.fips_state = fips_state;
		t.nSchoolClosureTimer = nSchoolClosureTimer;
		for(int i = 0; i < 9; i++) t.bSchoolClosed[i] = bSchoolClosed[i];
	}

	__device__ static bool isSchoolClosed(const dTract& t, int which){ return t.bSchoolClosed[which]; }
	__device__ static void setSchoolOpen(dTract &t, int which) { t.bSchoolClosed[which]=false; }
	__device__ static enum antiviralPolicy getAVPolicy(const dTract &t) { return (enum antiviralPolicy)(t.status&0x03); }
	__device__ static void setAVPolicy(dTract &t, enum antiviralPolicy p) { t.status|=p;} 
	__device__ static bool isQuarantine(const dTract &t) { return t.status&TRACTQUARANTINE; }
	__device__ static void setQuarantine(dTract &t) {t.status|=TRACTQUARANTINE;}
	__device__ static void setSchoolClosed(dTract &t, int which) { t.bSchoolClosed[which]=true; }
	__device__ static bool isVaccinated(const dTract &t) { return t.status&TRACTVACCINATED; } 
	__device__ static void setVaccinated(dTract &t) {t.status|=TRACTVACCINATED;}
};

/*********** model parameters ***********/
__device__ __constant__ double dvload[VLOADNSUB][VLOADNDAY];
__device__ __constant__ double dseasonality[MAXRUNLENGTH];
__device__ __constant__ double dfVaccineEfficacyByAge[TAG];
__device__ __constant__ vaccinedatastruct dVaccineData[NUMVACCINES];
__device__ __constant__ double dcpfc[TAG];
__device__ __constant__ double dcpfa[TAG];
__device__ __constant__ double dcphcc[TAG];
__device__ __constant__ double dcphca[TAG];
__device__ __constant__ unsigned int dwithdrawcdf32[3][WITHDRAWDAYS];
__device__ __constant__ unsigned int dincubationcdf32[3];
__device__ __constant__ double dcps[10];
__device__ __constant__ double d_travel_length_cdf[12];
__device__ __constant__ double d_travel_pr[TAG];
__device__ __constant__ int dnSchoolOpeningDays[56];
__device__ __constant__ unsigned char dnVaccinePriorities2[PRIORITY_LAST];

#define dnQuarantineLength 7
#define ddefaultboostday 21
#define dnAntiviralCourseSize 10
#define dfStopAntiviralTwoPills 0.05

__device__ const double ddefaultvacceff[VACCEFFLENGTH+1] = 
{0,0.001,0.004,0.011,0.023,0.043,0.07,0.106,0.153,0.211,0.28,0.363,0.46,0.572,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.7,0.702,0.71,0.73,0.766,0.82,0.897,1}; // initially in epimodel.cpp, since it is not in header, so I copied here


/********** infection functions *******/
struct InfectOp{
	dPerson* p_p;
	const dPerson* p_source;
	double baseprob;
	int sourcetype;
	
	RandGen* p_rand_obj;
	int timer;	
	double AVEp;
	double fSymptomaticAscertainment;
	int bTrigger;
	double fLiberalLeaveCompliance;
	double fIsolationCompliance;
	
	dCommunity* comm_vec;
	
	__device__
	InfectOp(dPerson& _p,
		const dPerson& _source,
		double _baseprob,
		int _sourcetype,
		RandGen& _rand_obj,
		int _timer,	
		double _AVEp,
		double _fSymptomaticAscertainment,
		int _bTrigger,
		double _fLiberalLeaveCompliance,
		double _fIsolationCompliance,
		dCommunity* _comm_vec){
		
		p_p = &_p;
		p_source = &_source;
		baseprob = _baseprob;
		sourcetype = _sourcetype;
		p_rand_obj = &_rand_obj;
		timer = _timer;	
		AVEp = _AVEp;
		fSymptomaticAscertainment = _fSymptomaticAscertainment;
		bTrigger = _bTrigger;
		fLiberalLeaveCompliance = _fLiberalLeaveCompliance;
		fIsolationCompliance = _fIsolationCompliance;
		comm_vec = _comm_vec;
	}

	__device__ 
	bool infect(){
		dPerson &p = *p_p;
		const dPerson &source = *p_source;
		RandGen &rand_obj = *p_rand_obj;
	
		if (rand_obj.cudaRandUni()<baseprob*p.prs*source.pri) {
			p.sourceid = source.id;
			p.sourcetype = sourcetype;
			p.nInfectedTime = timer;
			infectIndividual();
			return true;
		}
		return false;
	}

	__device__ 
	void infectIndividual(){
		dPerson &p = *p_p;
		RandGen &rand_obj = *p_rand_obj;
	
		dPerson::clearSusceptible(p); // no longer susceptible
	    dPerson::setInfected(p);           // infected
		// length of incubation period
	    p.iday=-1;  // set to -1 so the person is not infectious until tomorrow
		p.ibits = 0;
	    double fSymptomaticProb=0.67;
		if (dPerson::isVaccinated(p)) {
                	if (dPerson::needsBoost(p))
                        	fSymptomaticProb*=(1.0-dVaccineData[dPerson::whichVaccine(p)].VEp*
                                        	ddefaultvacceff[p.vday]*dfVaccineEfficacyByAge[p.age]);
                	else
                        	fSymptomaticProb*=(1.0-dVaccineData[dPerson::whichVaccine(p)].VEp*
                                        	dVaccineData[dPerson::whichVaccine(p)].vacceff[p.vday]*
	                                        dfVaccineEfficacyByAge[p.age]);
        	}
		
		if (dPerson::isAntiviral(p)) fSymptomaticProb*=(1.0-AVEp);

		double rn = rand_obj.cudaRandUni();
		if (rn<fSymptomaticProb) {  // will be symptomatic
			dPerson::setWillBeSymptomatic(p);
			unsigned int rn32 = rand_obj.cudaRandInt();
			if (rn32 < dincubationcdf32[0])
				dPerson::setIncubationDays(p,1);
			else if (rn32 < dincubationcdf32[1])
				dPerson::setIncubationDays(p,2);
			else
				dPerson::setIncubationDays(p,3);
			if (rn<fSymptomaticProb*fSymptomaticAscertainment) { // will be ascertained
				dPerson::setWillBeAscertained(p);
			}

			rn32 = rand_obj.cudaRandInt();
			unsigned int *wdcdf = dwithdrawcdf32[dPerson::isChild(p)?p.age:2];
			if (rn32<wdcdf[0])
				dPerson::setWithdrawDays(p,dPerson::getIncubationDays(p)+0);
			else if (rn32<wdcdf[1])
				dPerson::setWithdrawDays(p,dPerson::getIncubationDays(p)+1);
			else if (rn32<wdcdf[2])
				dPerson::setWithdrawDays(p,dPerson::getIncubationDays(p)+2);
			else
				dPerson::setWithdrawDays(p,0); // will not withdraw


			if (bTrigger && (dPerson::getWithdrawDays(p)==0 || // doesn't voluntarily withdraw
			dPerson::getWithdrawDays(p)-dPerson::getIncubationDays(p)>1)) { // would withdraw later
				if ((fLiberalLeaveCompliance > 0.0 && dPerson::isWorkingAge(p) && p.nWorkplace > 0
				&& rand_obj.cudaRandUni() < fLiberalLeaveCompliance) || // on liberal leave
				(fIsolationCompliance > 0.0 && rand_obj.cudaRandUni() < fIsolationCompliance)){ 
					dPerson::setWithdrawDays(p,dPerson::getIncubationDays(p)+1);
				}
			}
		}else{                
			// will NOT be symptomatic
            dPerson::setIncubationDays(p,0);
            dPerson::setWithdrawDays(p,0);   // note: withdraw days is only checked when symptomatic
		}
		if (p.nTravelTimer<=0) {
			atomicAdd(&(comm_vec[p.nHomeComm].ninf[p.age]),1);
            atomicAdd(&(comm_vec[p.nHomeComm].nEverInfected[p.age]),1);
        }
	}
};

/*********** day functions *************/
void cudaDay();

// infect from home and home workers
__device__ inline void dayInfectSusceptibles(
	const dPerson& infected, dCommunity& comm, // original arguments
	dPerson* ppl_vec,dTract* tract_vec,dCommunity* comm_vec,RandGen* rand_vec,
	int timer,	
	double AVEp,
	double fSymptomaticAscertainment,
	int bTrigger,
	double fLiberalLeaveCompliance,
	double fIsolationCompliance,
	bool bTravel,
	dCommWorker* comm_worker_vec, unsigned int comm_worker_start_idx, unsigned int comm_worker_end_idx,
	dCommVisitor* comm_visitor_vec, unsigned int comm_visitor_start_idx, unsigned int comm_visitor_end_idx,
	int* mutex, int target_value){
	
	const double *cpf = (dPerson::isChild(infected) ? dcpfc : dcpfa);
	// infected is at home during the day
	bool bInfectedAtHome = (dPerson::isWithdrawn(infected)
			|| dPerson::isQuarantined(infected) || infected.nWorkplace == 0
			|| (dPerson::isChild(infected) && infected.nWorkplace < 9
					&& dTract::isSchoolClosed(tract_vec[infected.nDayTract],
							infected.nWorkplace)));

	// infected's school or playgroup is open (playgroups are always open)
	bool bInfectedAtSchool = (dPerson::isChild(infected)
			&& infected.nWorkplace > 0
			&& ((infected.age == 0 && infected.nWorkplace >= 9)
			|| !dTract::isSchoolClosed(tract_vec[infected.nDayTract],infected.nWorkplace)));

	// infected works during the day
	bool bInfectedAtWork = (dPerson::isWorkingAge(infected)
			&& infected.nWorkplace > 0);

	double casualmultiplier = 1.0; // casual contacts multiplier for children
	if ((infected.age == 1 || (infected.age == 0 && infected.nWorkplace < 9))
		&& dTract::isSchoolClosed(tract_vec[infected.nDayTract],infected.nWorkplace))
		casualmultiplier = 2.0; // casual contacts double for out-of-school children

	for (unsigned int pid2 = comm.nFirstPerson; pid2 < comm.nLastPerson; pid2++) {
		dPerson &p2 = ppl_vec[pid2];
		
		
		if (dPerson::isSusceptible(p2) && p2.nDayComm == comm.id
		&& p2.nTravelTimer <= 0) {
			if (infected.family == p2.family
			&& // daytime transmission within household
			bInfectedAtHome
			&& (dPerson::isQuarantined(p2) || p2.nWorkplace == 0
			|| (dPerson::isChild(p2) && p2.nWorkplace < 9
			&& dTract::isSchoolClosed(tract_vec[comm.nTractID],p2.nWorkplace)))) {
					// susceptible is at home
				InfectOp new_infect(p2,infected,cpf[p2.age],FROMFAMILY,rand_vec[comm.id],timer,AVEp,
									fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
									fIsolationCompliance,comm_vec);
				if (new_infect.infect()) continue;
			}
				
			double casualmultiplier2 = casualmultiplier; // casual contacts multiplier for children
			if (casualmultiplier2==1.0 && (p2.age==1 || (p2.age==0 && p2.nWorkplace<9)) 
			&& dTract::isSchoolClosed(tract_vec[p2.nDayTract],p2.nWorkplace))
				casualmultiplier2 = 2.0;      // casual contacts double for out-of-school children
			
			InfectOp new_infect(p2,infected,comm.daycpcm[p2.age]*casualmultiplier2,FROMCOMMUNITY,
								rand_vec[comm.id],timer,AVEp,
								fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
								fIsolationCompliance,comm_vec);
									
			if (!dPerson::isQuarantined(p2) && !new_infect.infect()) { 
				if (infected.nDayNeighborhood==p2.nDayNeighborhood){ // transmission within neighborhood
					InfectOp new_infect1(p2,infected,comm.daycpnh[p2.age]*casualmultiplier2,FROMNEIGHBORHOOD,
										rand_vec[comm.id],timer,AVEp,
										fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
										fIsolationCompliance,comm_vec);
					if (new_infect1.infect()) continue;
				}	
				if (dPerson::isChild(infected)) {  // transmitter is child
					if (bInfectedAtSchool && dPerson::isChild(p2) && infected.nWorkplace==p2.nWorkplace){
						InfectOp new_infect2(p2,infected,
							(infected.nWorkplace>=9?dcps[9]:comm.cps[infected.nWorkplace]),FROMSCHOOL,
							rand_vec[comm.id],timer,AVEp,
							fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
							fIsolationCompliance,comm_vec);
						new_infect2.infect();
					}
				} else {           
					// transmitter is adult
					if (bInfectedAtWork && dPerson::isWorkingAge(p2) && infected.nWorkplace==p2.nWorkplace){
						// transmission within work group
						InfectOp new_infect3(p2,infected,0.05,FROMWORK,
							rand_vec[comm.id],timer,AVEp,
							fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
							fIsolationCompliance,comm_vec);
						new_infect3.infect();
					}
				}
			}
		}
		
	} // end big for loop
	
	Barrier(mutex,target_value);  
	
	// infection for outsider workers
	for (unsigned int i = comm_worker_start_idx; i < comm_worker_end_idx; i++) {
		dPerson &p2 = ppl_vec[comm_worker_vec[i].worker_id];
		if (dPerson::isSusceptible(p2) && ! dPerson::isQuarantined(p2) && p2.nTravelTimer<=0) {
			InfectOp new_infect1(p2,infected,comm.daycpcm[p2.age]*casualmultiplier,FROMCOMMUNITY,
				rand_vec[comm.id],timer,AVEp,
				fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
				fIsolationCompliance,comm_vec);
			
			if (!new_infect1.infect()) { // transmission within community
				if (infected.nDayNeighborhood==p2.nDayNeighborhood){  // transmission within neighborhood
					InfectOp new_infect2(p2,infected,comm.daycpnh[p2.age]*casualmultiplier,FROMNEIGHBORHOOD,
						rand_vec[comm.id],timer,AVEp,
						fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
						fIsolationCompliance,comm_vec);
					
					if (new_infect2.infect()) continue;
				}
				if (dPerson::isWorkingAge(infected) && infected.nWorkplace==p2.nWorkplace) {
					// transmit to coworkers from other tracts
					InfectOp new_infect3(p2,infected,0.05,FROMWORK,
						rand_vec[comm.id],timer,AVEp,
						fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
						fIsolationCompliance,comm_vec);
					
					new_infect3.infect();
				}
			}
		}
	}
	
	Barrier(mutex+1,target_value); 
	
	// infect visitors
	if (bTravel){
		for (unsigned int i = comm_visitor_start_idx; i < comm_visitor_end_idx; i++) {
			dPerson &p2 = comm_visitor_vec[i].visitor;
			if (dPerson::isSusceptible(p2)) { 
				InfectOp new_infect1(p2,infected,comm.daycpcm[p2.age]*casualmultiplier,FROMCOMMUNITY,
					rand_vec[comm.id],timer,AVEp,
					fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
					fIsolationCompliance,comm_vec);
					
				if (!new_infect1.infect()) { // transmission within community
					if (infected.nDayNeighborhood==p2.nDayNeighborhood){
						InfectOp new_infect2(p2,infected,comm.daycpnh[p2.age]*casualmultiplier,FROMNEIGHBORHOOD,
							rand_vec[comm.id],timer,AVEp,
							fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
							fIsolationCompliance,comm_vec);
						if (new_infect2.infect())
							continue;
					}
					if (dPerson::isWorkingAge(infected) && 
						dPerson::isWorkingAge(p2) && infected.nWorkplace==p2.nWorkplace && p2.nWorkplace>0){
						
						InfectOp new_infect3(p2,infected,0.05,FROMWORK,
							rand_vec[comm.id],timer,AVEp,
							fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
							fIsolationCompliance,comm_vec);
							
						new_infect3.infect();
					}	
				}
			}
		}
	}
	
	Barrier(mutex+2,target_value); 
}

// calculate daytime susceptibility and infectiousness for each person
struct DayOp1{
	int timer;
	double AVEs,AVEi;

	DayOp1(int _timer,double _AVEs, double _AVEi){
		timer = _timer;
		AVEs = _AVEs; AVEi = _AVEi;
	}

	__device__
	void operator()(dPerson& p){
		p.prs = 1.0 - p.fBaselineVES;
		if(dPerson::isInfectious(p)) 
			p.pri = dvload[p.nWhichVload][(int)(p.iday)] * dseasonality[timer/2]; 
		else 
			p.pri = 0.0;
		if(dPerson::isVaccinated(p)){
			if (dPerson::needsBoost(p)){
			p.prs *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEs*
				ddefaultvacceff[p.vday]*dfVaccineEfficacyByAge[p.age]);
			p.pri *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEi*
				ddefaultvacceff[p.vday]*dfVaccineEfficacyByAge[p.age]);
      			} else {
			p.prs *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEs*
				dVaccineData[dPerson::whichVaccine(p)].vacceff[p.vday]*
				dfVaccineEfficacyByAge[p.age]);
			p.pri *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEi*
				dVaccineData[dPerson::whichVaccine(p)].vacceff[p.vday]*
				dfVaccineEfficacyByAge[p.age]);
      			}
		}
		if(dPerson::isAntiviral(p)){
			p.prs *= (1.0-AVEs);
      			p.pri *= (1.0-AVEi);
		}
		if (dPerson::isSymptomatic(p)) p.pri *= 2.0; 
	}
};

// calculate daytime susceptiblity and infectious for each visitors
struct DayOp2{
	double AVEs,AVEi;

	DayOp2(double _AVEs, double _AVEi){
		AVEs = _AVEs; AVEi = _AVEi;
	}

	__device__ 
	void operator()(dCommVisitor& comm_visitor){
		dPerson &p = comm_visitor.visitor;
		p.prs = 1.0 - p.fBaselineVES;
		if(dPerson::isInfectious(p)) 
			p.pri = dvload[p.nWhichVload][(int)(p.iday)]; 
		else 
			p.pri = 0.0;
		if(dPerson::isVaccinated(p)){
			if (dPerson::needsBoost(p)){
			p.prs *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEs*
				ddefaultvacceff[p.vday]*dfVaccineEfficacyByAge[p.age]);
			p.pri *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEi*
				ddefaultvacceff[p.vday]*dfVaccineEfficacyByAge[p.age]);
      			} else {
			p.prs *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEs*
				dVaccineData[dPerson::whichVaccine(p)].vacceff[p.vday]*
				dfVaccineEfficacyByAge[p.age]);
			p.pri *= (1.0-dVaccineData[dPerson::whichVaccine(p)].VEi*
				dVaccineData[dPerson::whichVaccine(p)].vacceff[p.vday]*
				dfVaccineEfficacyByAge[p.age]);
      			}
		}
		if(dPerson::isAntiviral(p)){
			p.prs *= (1.0-AVEs);
      			p.pri *= (1.0-AVEi);
		}
		if (dPerson::isSymptomatic(p)) p.pri *= 2.0; 
	}		
};	
	
__global__ inline void DayOp3Improve(
	dPerson* ppl_vec, dTract* tract_vec,dCommunity* comm_vec,RandGen* rand_vec,
	int timer, double AVEp, double fSymptomaticAscertainment, int bTrigger,
	double fLiberalLeaveCompliance, double fIsolationCompliance, bool bTravel,
	dCommWorker* comm_worker_vec, unsigned int* comm_worker_start_vec, unsigned int* comm_worker_end_vec,
	dCommVisitor* comm_visitor_vec, unsigned int* comm_visitor_start_vec, unsigned int* comm_visitor_end_vec,
	int* mutex){
	
	int tid = threadIdx.x;
	int bid = blockIdx.x;
	
	dCommunity& comm = comm_vec[bid];
	
	int target_value = gridDim.x * gridDim.y*gridDim.z;
	unsigned int comm_worker_start_idx = comm_worker_start_vec[bid];
	unsigned int comm_worker_end_idx = comm_worker_end_vec[bid];
	unsigned int comm_visitor_start_idx = comm_visitor_start_vec[bid];
	unsigned int comm_visitor_end_idx = comm_visitor_end_vec[bid];
	
	int thread_len = 
		(comm_worker_end_idx - comm_worker_start_idx) / blockDim.x + 
		((comm_worker_end_idx - comm_worker_start_idx) % blockDim.x != 0);
	
	int local_start_idx = comm_worker_start_idx  + tid * thread_len;
	int local_end_idx = local_start_idx + thread_len;
	local_end_idx = local_end_idx < comm_worker_end_idx ? local_end_idx : comm_worker_end_idx;
	
	if (comm.ninf[0]>0 || comm.ninf[1]>0 || comm.ninf[2]>0 || comm.ninf[3]>0 || comm.ninf[4]>0){
		for(unsigned int pid = local_start_idx; pid < local_end_idx; pid++){
			dPerson &p = ppl_vec[pid];
			if (dPerson::isInfectious(p) && !dPerson::isWithdrawn(p) && 
			!dPerson::isQuarantined(p) && p.nDayComm==comm.id && p.nTravelTimer<=0) {
					
				dayInfectSusceptibles(p,comm,ppl_vec,tract_vec,comm_vec,rand_vec,timer,AVEp,
					fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
					fIsolationCompliance,bTravel,
					comm_worker_vec,comm_worker_start_idx,comm_worker_end_idx,
					comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
					mutex, target_value);
			}
		}			
	}
		
		
	for (unsigned int i = local_start_idx; i < local_end_idx; i++){
		dPerson &p = ppl_vec[comm_worker_vec[i].worker_id];
		if (dPerson::isInfectious(p) && !dPerson::isWithdrawn(p) && 
			!dPerson::isQuarantined(p) && p.nTravelTimer<=0)
				dayInfectSusceptibles(p,comm,ppl_vec,tract_vec,comm_vec,rand_vec,timer,AVEp,
					fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
					fIsolationCompliance,bTravel,
					comm_worker_vec,comm_worker_start_idx,comm_worker_end_idx,
					comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
					mutex+3, target_value);
	}
};
	
struct DayOp3{
	dPerson* ppl_vec;
	dTract* tract_vec;
	dCommunity* comm_vec;
	RandGen* rand_vec;
	
	int timer;	
	double AVEp;
	double fSymptomaticAscertainment;
	int bTrigger;
	double fLiberalLeaveCompliance;
	double fIsolationCompliance;
	bool bTravel;
	
	dCommWorker* comm_worker_vec; 
	unsigned int* comm_worker_start_vec;
	unsigned int* comm_worker_end_vec;
	dCommVisitor* comm_visitor_vec;
	unsigned int* comm_visitor_start_vec;
	unsigned int* comm_visitor_end_vec;
	
	int* mutex; int target_value;
	
	DayOp3(dPerson* _ppl_vec, dTract* _tract_vec,dCommunity* _comm_vec,RandGen* _rand_vec,
		int _timer, double _AVEp, double _fSymptomaticAscertainment, int _bTrigger,
		double _fLiberalLeaveCompliance, double _fIsolationCompliance, bool _bTravel,
		dCommWorker* _comm_worker_vec, unsigned int* _comm_worker_start_vec, unsigned int* _comm_worker_end_vec,
		dCommVisitor* _comm_visitor_vec, unsigned int* _comm_visitor_start_vec, unsigned int* _comm_visitor_end_vec,
		int* _mutex){
		
		ppl_vec = _ppl_vec; 
		tract_vec = _tract_vec;
		comm_vec = _comm_vec;
		rand_vec = _rand_vec;
		
		timer = _timer;
		AVEp = _AVEp;
		fSymptomaticAscertainment = _fSymptomaticAscertainment;
		bTrigger = _bTrigger;
		fLiberalLeaveCompliance = _fLiberalLeaveCompliance;
		fIsolationCompliance = _fIsolationCompliance;
		bTravel = _bTravel;
		
		comm_worker_vec = _comm_worker_vec; 
		comm_worker_start_vec = _comm_worker_start_vec;
		comm_worker_end_vec = _comm_worker_end_vec;
		comm_visitor_vec = _comm_visitor_vec;
		comm_visitor_start_vec = _comm_visitor_start_vec;
		comm_visitor_end_vec = _comm_visitor_end_vec;
		
		mutex = _mutex;
	}	

	__device__
	void operator()(dCommunity& comm){
		int target_value = gridDim.x * gridDim.y*gridDim.z;
		unsigned int comm_worker_start_idx = comm_worker_start_vec[comm.id];
		unsigned int comm_worker_end_idx = comm_worker_end_vec[comm.id];
		unsigned int comm_visitor_start_idx = comm_visitor_start_vec[comm.id];
		unsigned int comm_visitor_end_idx = comm_visitor_end_vec[comm.id];
	
		if (comm.ninf[0]>0 || comm.ninf[1]>0 || comm.ninf[2]>0 || comm.ninf[3]>0 || comm.ninf[4]>0){
			for(unsigned int pid = comm.nFirstPerson; pid < comm.nLastPerson; pid++){
				dPerson &p = ppl_vec[pid];
				if (dPerson::isInfectious(p) && !dPerson::isWithdrawn(p) && 
				!dPerson::isQuarantined(p) && p.nDayComm==comm.id && p.nTravelTimer<=0) {
					
					dayInfectSusceptibles(p,comm,ppl_vec,tract_vec,comm_vec,rand_vec,timer,AVEp,
						fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
						fIsolationCompliance,bTravel,
						comm_worker_vec,comm_worker_start_idx,comm_worker_end_idx,
						comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
						mutex, target_value);
				}
			}			
		}
		
		
		for (unsigned int i = comm_worker_start_idx; i < comm_worker_end_idx; i++){
			dPerson &p = ppl_vec[comm_worker_vec[i].worker_id];
			if (dPerson::isInfectious(p) && !dPerson::isWithdrawn(p) && 
				!dPerson::isQuarantined(p) && p.nTravelTimer<=0)
					dayInfectSusceptibles(p,comm,ppl_vec,tract_vec,comm_vec,rand_vec,timer,AVEp,
						fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
						fIsolationCompliance,bTravel,
						comm_worker_vec,comm_worker_start_idx,comm_worker_end_idx,
						comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
						mutex+3, target_value);
		}
		
		if (bTravel) {
			for (unsigned int i = comm_visitor_start_idx; i < comm_visitor_end_idx; i++) {
				dPerson &p = comm_visitor_vec[i].visitor;
				if (dPerson::isInfectious(p) && !dPerson::isWithdrawn(p)) // && !isQuarantined(p))
					dayInfectSusceptibles(p,comm,ppl_vec,tract_vec,comm_vec,rand_vec,timer,AVEp,
						fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
						fIsolationCompliance,bTravel,
						comm_worker_vec,comm_worker_start_idx,comm_worker_end_idx,
						comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
						mutex+6, target_value);
			}
		}
	}
};


/****** travel functions **********/
void cudaTravelEnd();

struct TravelEndOp{
	dPerson* ppl_vec;
	dCommunity* comm_vec;
	
	
	TravelEndOp(dPerson* _ppl_vec, dCommunity* _comm_vec){
		ppl_vec = _ppl_vec;
		comm_vec = _comm_vec;
	}
	
	__device__
	void operator()(dCommVisitor& comm_visitor){
		dPerson &p = comm_visitor.visitor;
		if (--p.nTravelTimer<=0) {
			dPerson &original = ppl_vec[p.id];
			if (dPerson::isInfected(p)) { // got sick on vacation
				if (!dPerson::isInfected(original)) {
					atomicAdd(&(comm_vec[original.nHomeComm].ninf[original.age]),1);
					atomicAdd(&(comm_vec[original.nHomeComm].nEverInfected[original.age]),1);
					original.nInfectedTime = p.nInfectedTime;
				}
				if (dPerson::isSymptomatic(p) && !dPerson::isSymptomatic(original)) {
					atomicAdd(&(comm_vec[original.nHomeComm].nEverSymptomatic[original.age]),1);
					atomicAdd(&(comm_vec[original.nHomeComm].nsym[original.age]),1);
				}
			} else if (dPerson::isInfected(original)) {
				atomicSub(&(comm_vec[original.nHomeComm].ninf[original.age]),1);
					
				if (!dPerson::isSymptomatic(p) && dPerson::isSymptomatic(original))
					atomicSub(&(comm_vec[original.nHomeComm].nsym[original.age]),1);
			}
			original.status = p.status;
			original.ibits = p.ibits;
			original.iday = p.iday;
			original.sourcetype = p.sourcetype;
			original.sourceid = p.sourceid;
			original.nTravelTimer = 0; // welcome home
				
			p.valid = false; // remove the visitor later
		}
	} // end for loop
};


struct TravelRemoveOp{

	__device__
	bool operator()(const dCommVisitor& comm_visitor){
		return !comm_visitor.visitor.valid;
	}
};

void cudaTravelStart();

struct TravelStartOp{
	dPerson* ppl_vec;
	dTract* tract_vec;
	dCommunity* comm_vec;
	RandGen* rand_vec;
	
	dCommVisitor* new_visitor_vec; // for my own purpose of adding new visitors
	
	unsigned int nNumTractsTotal;
	
	TravelStartOp(dPerson* _ppl_vec, dTract* _tract_vec, dCommunity* _comm_vec,
		RandGen* _rand_vec,dCommVisitor* _new_visitor_vec,
		unsigned int _nNumTractsTotal){
		
		ppl_vec = _ppl_vec;
		tract_vec = _tract_vec;
		comm_vec = _comm_vec;
		rand_vec = _rand_vec;
	
		new_visitor_vec = _new_visitor_vec;
		
		nNumTractsTotal = _nNumTractsTotal;
	}
	
	__device__
	void operator()(dPerson& p){
		RandGen& rand_obj = rand_vec[p.id];
		
		if (p.nTravelTimer<=0 && !dPerson::isQuarantined(p) && rand_obj.cudaRandUni() < d_travel_pr[p.age]) {
		
			// We're going to DisneyWorld!
			double r = rand_obj.cudaRandUni();
			int i;
			for (i=0; r>d_travel_length_cdf[i]; i++);
			p.nTravelTimer = i+1;
			unsigned int destinationtract = rand_obj.cudaRandInt() % nNumTractsTotal;
			
			unsigned int destinationcomm = tract_vec[destinationtract].nFirstCommunity;
			int diff = tract_vec[destinationtract].nLastCommunity - tract_vec[destinationtract].nFirstCommunity;
			if (diff>1) destinationcomm += rand_obj.cudaRandInt() % diff;
	
			dPerson& traveler = new_visitor_vec[p.id].visitor;
			traveler = p;
			
			traveler.nDayTract = destinationtract;
			traveler.nHomeComm = destinationcomm;
			traveler.nDayComm = destinationcomm;
			traveler.nDayNeighborhood = rand_obj.cudaRandInt() % 4;
			diff = comm_vec[destinationcomm].nLastPerson-comm_vec[destinationcomm].nFirstPerson;
			if (diff>0) {
				// assign a host family to the traveler
				dPerson &host = ppl_vec[comm_vec[destinationcomm].nFirstPerson + (rand_obj.cudaRandInt() % diff)];
				traveler.family = host.family;
				traveler.householdcluster = host.householdcluster;
				traveler.nHomeNeighborhood = host.nHomeNeighborhood;
				if (dPerson::isWorkingAge(traveler) && comm_vec[destinationcomm].nNumWorkGroups>0)
					traveler.nWorkplace = 1+(rand_obj.cudaRandInt() % comm_vec[destinationcomm].nNumWorkGroups);
				else
					traveler.nWorkplace = 0;
			}
		}else{
			new_visitor_vec[p.id].visitor.valid = false;
		}
		
	}
};


/******* night functions *************/
void cudaNight();


__device__ void nightInfectSusceptibles(
	const dPerson& infected,dCommunity& comm,
	dPerson* ppl_vec,dCommunity* comm_vec,RandGen* rand_vec,
	int timer,	
	double AVEp,
	double fSymptomaticAscertainment,
	int bTrigger,
	double fLiberalLeaveCompliance,
	double fIsolationCompliance,
	bool bTravel,
	dCommVisitor* comm_visitor_vec, unsigned int comm_visitor_start_idx, unsigned int comm_visitor_end_idx,
	int* mutex, int target_value);

struct NightOp{
	dPerson* ppl_vec;
	dTract* tract_vec;
	dCommunity* comm_vec;
	RandGen* rand_vec;
	
	int timer;	
	double AVEp;
	double fSymptomaticAscertainment;
	int bTrigger;
	double fLiberalLeaveCompliance;
	double fIsolationCompliance;
	double fQuarantineCompliance;
	bool bTravel;
	int nAscertainmentDelay;
	double fContactAscertainment;

	unsigned int* nNumTAPDone;
	unsigned int* nNumWantAV;
	
	dCommVisitor* comm_visitor_vec;
	unsigned int* comm_visitor_start_vec;
	unsigned int* comm_visitor_end_vec;
	
	int* mutex; int target_value;
	int* TAP_mutex_1;
	int* TAP_mutex_2;
	
	NightOp(dPerson* _ppl_vec,dTract* _tract_vec,dCommunity* _comm_vec,RandGen* _rand_vec,
		int _timer, double _AVEp, double _fSymptomaticAscertainment, int _bTrigger,
		double _fLiberalLeaveCompliance, double _fIsolationCompliance, double _fQuarantineCompliance, 
		bool _bTravel, int _nAscertainmentDelay,double _fContactAscertainment,
		unsigned int* _nNumTAPDone, unsigned int* _nNumWantAV,
		dCommVisitor* _comm_visitor_vec, unsigned int* _comm_visitor_start_vec, unsigned int* _comm_visitor_end_vec,
		int* _mutex, int* _TAP_mutex_1, int* _TAP_mutex_2){
	
		ppl_vec = _ppl_vec; 
		tract_vec = _tract_vec;
		comm_vec = _comm_vec;
		rand_vec = _rand_vec;
		
		timer = _timer;
		AVEp = _AVEp;
		fSymptomaticAscertainment = _fSymptomaticAscertainment;
		bTrigger = _bTrigger;
		fLiberalLeaveCompliance = _fLiberalLeaveCompliance;
		fIsolationCompliance = _fIsolationCompliance;
		fQuarantineCompliance = _fQuarantineCompliance;
		bTravel = _bTravel;
		nAscertainmentDelay = _nAscertainmentDelay;
		fContactAscertainment = _fContactAscertainment;
		
		nNumTAPDone = _nNumTAPDone;
		nNumWantAV = _nNumWantAV;
		
		comm_visitor_vec = _comm_visitor_vec;
		comm_visitor_start_vec = _comm_visitor_start_vec;
		comm_visitor_end_vec = _comm_visitor_end_vec;
		
		mutex = _mutex;
		TAP_mutex_1 = _TAP_mutex_1;
		TAP_mutex_2 = _TAP_mutex_2;
		
	}
	
	__device__ void TAP(dPerson& p, RandGen& rand_obj){
		dCommunity& c = comm_vec[p.nDayComm];
		if (dPerson::isAVProphylaxis(p)) dPerson::clearAVProphylaxis(p);
		
		enum antiviralPolicy policy = dTract::getAVPolicy(tract_vec[c.nTractID]);
		
		bool is_first_branch = true;
		
		if (policy==HHTAP || policy==FULLTAP) {
			
			EnterCS(TAP_mutex_2);
			
			if(policy==HHTAP100 && nNumTAPDone[0] <100)
				nNumTAPDone[0]++;
			else
				is_first_branch = false;
			
			QuitCS(TAP_mutex_2);
		}else{ 
			is_first_branch = false;
		}
		
		EnterCS(TAP_mutex_1+c.id);
		
		if(is_first_branch){
			for (unsigned int i=c.nFirstPerson; i<c.nLastPerson; i++) {
				dPerson &target = ppl_vec[i];
				
				
				
				if (!target.bWantAV && 
				!dPerson::isAntiviral(target) &&       // not already on antivirals
				!dPerson::isAVProphylaxis(target) &&   // not already waiting for AV prophylaxis
				(p.family == target.family || // family member
				(policy==FULLTAP && 
				(p.householdcluster == target.householdcluster || // in household cluster
				(dPerson::isChild(p) && dPerson::isChild(target) && p.nWorkplace==target.nWorkplace && 
				(p.nWorkplace>=5 ||  // in daycare or playgroup
				rand_obj.cudaRandUni()<fContactAscertainment)))))) { // in elementary/middle/high
	
					if (p.id!=target.id) dPerson::setAVProphylaxis(target); // prophylaxis, not treatment
	
					target.bWantAV=true;
					atomicAdd(&(nNumWantAV[0]),1);
				}

				
			}
		}else{
		
			if (!p.bWantAV && !dPerson::isAntiviral(p) && !dPerson::isAVProphylaxis(p)) {
				p.bWantAV=true;
				atomicAdd(&(nNumWantAV[0]),1);
			}
		}
		
		QuitCS(TAP_mutex_1+c.id);

	}
	
	
	__device__
	void operator()(dCommunity& comm){
		RandGen& rand_obj = rand_vec[comm.id];
	
		int target_value = gridDim.x * gridDim.y*gridDim.z;
		unsigned int comm_visitor_start_idx = comm_visitor_start_vec[comm.id];
		unsigned int comm_visitor_end_idx = comm_visitor_end_vec[comm.id];
	
		if (comm.ninf[0]>0 || comm.ninf[1]>0 || comm.ninf[2]>0 || comm.ninf[3]>0 || comm.ninf[4]>0) { 
			for(unsigned int pid=comm.nFirstPerson;pid<comm.nLastPerson;pid++) {
				dPerson &p = ppl_vec[pid];
				if (dPerson::isInfectious(p) && p.nTravelTimer<=0)
					nightInfectSusceptibles(p, comm,ppl_vec,comm_vec,rand_vec,timer,AVEp,
						fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
						fIsolationCompliance,bTravel,
						comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
						mutex, target_value);
			}
		}
	
	
		if (bTravel) {

			for (unsigned int i = comm_visitor_start_idx; i < comm_visitor_end_idx; i++) {
				dPerson &p = comm_visitor_vec[i].visitor;
				if (dPerson::isInfectious(p) && !dPerson::isWithdrawn(p))
					nightInfectSusceptibles(p, comm,ppl_vec,comm_vec,rand_vec,timer,AVEp,
								fSymptomaticAscertainment,bTrigger,fLiberalLeaveCompliance,
								fIsolationCompliance,bTravel,
								comm_visitor_vec,comm_visitor_start_idx,comm_visitor_end_idx,
								mutex+2, target_value);
			}
		}

		// update infection and intervention status (timers)
		for (unsigned int pid=comm.nFirstPerson; pid<comm.nLastPerson; pid++) {
			dPerson &p = ppl_vec[pid];
			if (dPerson::isInfected(p)) {
				if (dPerson::isInfectious(p)) {
					if (dPerson::getWillBeSymptomatic(p) && p.iday==dPerson::getIncubationDays(p)) {
						dPerson::setSymptomatic(p);
						atomicAdd(&(comm_vec[p.nHomeComm].nEverSymptomatic[p.age]),1);
						atomicAdd(&(comm_vec[p.nHomeComm].nsym[p.age]),1);
					}
					if (dPerson::isSymptomatic(p)) {
						if (p.iday==dPerson::getIncubationDays(p)+nAscertainmentDelay 
						&& dPerson::getWillBeAscertained(p)) { // person becomes ascertained
						
							atomicAdd(&(comm_vec[p.nHomeComm].nEverAscertained[p.age]),1);
					
							// call TAP when cases are ascertained in this tract
							if (dTract::getAVPolicy(tract_vec[comm.nTractID])!=NOAV) TAP(p,rand_obj);
					
		
							// quarantine the family
							if (dTract::isQuarantine(tract_vec[comm.nTractID]) && 
							p.iday==dPerson::getIncubationDays(p)+1) {
								for (unsigned int pid2=comm.nFirstPerson; pid2<comm.nLastPerson; pid2++) {
									dPerson &p2 = ppl_vec[pid2];
									if (p.family==p2.family && p.id!=p2.id && 
										rand_obj.cudaRandUni()<fQuarantineCompliance) { // quarantine family member
								
										dPerson::setQuarantined(p2);  // household quarantine
										p2.nQuarantineTimer = dnQuarantineLength + 1;
									}
								}
							}
						}
						if (dPerson::getWithdrawDays(p)>0 && p.iday==(int)dPerson::getWithdrawDays(p))
							dPerson::setWithdrawn(p);              // withdraw to home
					}	
				}
				p.iday++;
				if (p.iday>=VLOADNDAY) {
					if (dPerson::isSymptomatic(p)) atomicSub(&(comm.nsym[p.age]),1);
				
					p.status &= ~(SUSCEPTIBLE|INFECTED|SYMPTOMATIC|WITHDRAWN); // recovered
	  
					atomicSub(&(comm.ninf[p.age]),1);
					p.iday=0;
				}
			}
				
			if (dPerson::isVaccinated(p) && p.vday<VACCEFFLENGTH && 
			(dPerson::isBoosted(p) ||
			p.vday<dVaccineData[dPerson::whichVaccine(p)].nBoostDay ||
			(!dPerson::needsBoost(p) &&
			dVaccineData[dPerson::whichVaccine(p)].nNumDoses==1) ||
			(dPerson::needsBoost(p) &&
			p.vday<ddefaultboostday))) p.vday++;
				
				
			if (dPerson::isQuarantined(p) && --p.nQuarantineTimer <= 0) {
				dPerson::clearQuarantined(p);  // quarantine over for this person
			}
				
			if (dPerson::isAntiviral(p)) {
				--p.nAVTimer;
	
				if (!dPerson::isAVProphylaxis(p)) --p.nAVTimer; // treatment requires 2nd tablet each day
								
				if (p.nAVTimer<=0 || 
				(p.nAVTimer==dnAntiviralCourseSize-2 && rand_obj.cudaRandUni()<dfStopAntiviralTwoPills)) {
					dPerson::clearAntiviral(p);    // antiviral over for this person
					dPerson::clearAVProphylaxis(p);
				}
			}
		}// big for loop
		
		
		// update visitors
		if (bTravel) {
			for (unsigned int i = comm_visitor_start_idx; i < comm_visitor_end_idx; i++) {
				dPerson &p = comm_visitor_vec[i].visitor;
				if (dPerson::isInfected(p)) {
					if (dPerson::isInfectious(p)) {
						if (p.iday == dPerson::getIncubationDays(p) && dPerson::getWillBeSymptomatic(p))
							dPerson::setSymptomatic(p);
							
						if (dPerson::getWithdrawDays(p) > 0 && p.iday == (int) dPerson::getWithdrawDays(p))
							dPerson::setWithdrawn(p); 	// withdraw to home
					}
					p.iday++;
					if (p.iday >= VLOADNDAY) {
						p.status &= ~(SUSCEPTIBLE | INFECTED | SYMPTOMATIC
								| WITHDRAWN); // recovered
						p.iday = 0;
					}
				}
				if (dPerson::isVaccinated(p) && p.vday < VACCEFFLENGTH
				&& (dVaccineData[dPerson::whichVaccine(p)].nNumDoses == 1
				|| p.vday < dVaccineData[dPerson::whichVaccine(p)].nBoostDay
				|| dPerson::isBoosted(p))) p.vday++;
			}
		}
	}
};

/********* response ************/
void cudaResponse();

struct ActOp0{
	int nTimer;
	
	ActOp0(int _nTimer){nTimer = _nTimer;}

	__device__
	void operator()(dTract& t){
		if (dTract::isSchoolClosed(t,1) && dnSchoolOpeningDays[t.fips_state-1]-1==nTimer/2) {
		for (int i=0; i<9; i++)
			dTract::setSchoolOpen(t,i);// schools open today
		t.nSchoolClosureTimer=0;
		}
	}
};

struct ActOp1{
	__device__
	int operator()(dCommunity& c){
		int nNumAscertained = 0;
		for (int j=0; j<TAG; j++)
			nNumAscertained += c.nEverAscertained[j];
		return nNumAscertained;
	}
};

__device__ 
bool inline isAscertained(const dPerson &p, int nAscertainmentDelay) {
	return dPerson::isInfectious(p) && dPerson::getWillBeSymptomatic(p) && 
	p.iday>=(dPerson::getIncubationDays(p)+nAscertainmentDelay);
};

struct VaccinateOp{
	dPerson* ppl_vec;
	dCommunity* comm_vec;
	unsigned int* nNumWantVaccine;
	int nAscertainmentDelay;
	
	__device__
	VaccinateOp(dPerson* _ppl_vec, dCommunity* _comm_vec,unsigned int* _nNumWantVaccine,int _nAscertainmentDelay){
		ppl_vec = _ppl_vec;
		comm_vec = _comm_vec;
		nNumWantVaccine = _nNumWantVaccine;
		nAscertainmentDelay = _nAscertainmentDelay;
	}
	
	__device__
	void vaccinate(dTract& t){

		if (!dTract::isVaccinated(t)) {
			dTract::setVaccinated(t);
			for (unsigned int commid=t.nFirstCommunity; commid<t.nLastCommunity; commid++) {
				dCommunity &comm = comm_vec[commid];
				for (unsigned int pid=comm.nFirstPerson;pid<comm.nLastPerson;pid++) {
					dPerson &p = ppl_vec[pid];
					vaccinate(p);
				}
			}
		}
	}
	
	__device__
	void vaccinate(dPerson& p){
		if (!dPerson::isBoosted(p) && p.nVaccinePriority>0 
		&& isAscertained(p,nAscertainmentDelay) && p.nTravelTimer<=0) {			
			p.bWantVac=true;
			atomicAdd(&(nNumWantVaccine[0]),1);
		}
	}
};

struct ActOp2{
	dPerson* ppl_vec;
	dCommunity* comm_vec;
	unsigned int* nNumWantVaccine;
	
	antiviralPolicy eAVPolicy;
	double fQuarantineCompliance;
	int nSchoolClosureDays;
	int nSchoolClosurePolicy;
	vaccType eVaccinationStrategy;
	int nAscertainmentDelay;
	
	ActOp2(dPerson* _ppl_vec,dCommunity* _comm_vec, unsigned int* _nNumWantVaccine,
		antiviralPolicy _eAVPolicy,double _fQuarantineCompliance,int _nSchoolClosureDays,
		int _nSchoolClosurePolicy,vaccType _eVaccinationStrategy,int _nAscertainmentDelay){
		
		ppl_vec = _ppl_vec; 
		comm_vec = _comm_vec;
		nNumWantVaccine = _nNumWantVaccine;
		
		eAVPolicy = _eAVPolicy;
		fQuarantineCompliance = _fQuarantineCompliance;
		nSchoolClosureDays = _nSchoolClosureDays;
		nSchoolClosurePolicy = _nSchoolClosurePolicy;
		eVaccinationStrategy = _eVaccinationStrategy;
		nAscertainmentDelay = _nAscertainmentDelay;
	
	}
	
	// return number of vaccine want in this tract
	__device__
	void operator()(dTract& t){
		if (eAVPolicy!=NOAV && dTract::getAVPolicy(t)!=eAVPolicy)
			dTract::setAVPolicy(t, eAVPolicy);         // start using antivirals in tract
		if (fQuarantineCompliance>0.0 && !dTract::isQuarantine(t))
			dTract::setQuarantine(t);  // activate household quarantine in tract
		if (nSchoolClosureDays>0 && nSchoolClosurePolicy==1) {
			if (!dTract::isSchoolClosed(t,1)) {
				for (int i=0; i<9; i++)
					dTract::setSchoolClosed(t,i);// activate school closures
				t.nSchoolClosureTimer=nSchoolClosureDays;
			}
		}

		VaccinateOp vacc_obj(ppl_vec, comm_vec,nNumWantVaccine,nAscertainmentDelay);
		if (eVaccinationStrategy==MASSVAC && !dTract::isVaccinated(t)) vacc_obj.vaccinate(t);
	}
	

};

struct ActOp3{
	dPerson* ppl_vec;

	unsigned int nNumPerson;
	unsigned char nHighestPriority;
	
	ActOp3(dPerson* _ppl_vec, unsigned int _nNumPerson, unsigned char _nHighestPriority){
		ppl_vec = _ppl_vec;
		nNumPerson = _nNumPerson;
		nHighestPriority = _nHighestPriority;
	}
	
	__device__
	void operator()(dPerson& p){
		if (p.nVaccinePriority>0) { // is this person already able to get vaccine?
			unsigned char priority = 100;
			if (dnVaccinePriorities2[PRIORITY_PREGNANT]>0 && dPerson::isPregnant(p))
				priority = dmin(dnVaccinePriorities2[PRIORITY_PREGNANT], priority);
			if (dnVaccinePriorities2[PRIORITY_ESSENTIAL]>0 && dPerson::isEssential(p))
				priority = dmin(dnVaccinePriorities2[PRIORITY_ESSENTIAL], priority);
			if (dnVaccinePriorities2[PRIORITY_HR0+p.age]>0 && dPerson::isHighRisk(p))
				priority = dmin(dnVaccinePriorities2[PRIORITY_HR0+p.age], priority);
			if (dnVaccinePriorities2[PRIORITY_0+p.age]>0)
				priority = dmin(dnVaccinePriorities2[PRIORITY_0+p.age], priority);
			if (dnVaccinePriorities2[PRIORITY_INFANTFAMILY]>0 && !dPerson::isInfant(p)) {
				unsigned int upper = (p.id+7>nNumPerson?nNumPerson:p.id+7);
				for (unsigned int i=(p.id>7?p.id-7:0); i<upper; i++){
					if (ppl_vec[i].family==p.family && dPerson::isInfant(ppl_vec[i])) {
						priority = dmin(dnVaccinePriorities2[PRIORITY_INFANTFAMILY], priority);
						i=upper;
					}
				}
			}
			if (priority>nHighestPriority)
				p.nVaccinePriority = 0;
			else
				p.nVaccinePriority = priority;
		}	
	}
	
};

struct ActOp41{
	dPerson* ppl_vec;
	dCommunity* comm_vec;
	unsigned int* nNumWantVaccine;
	int nAscertainmentDelay;
	
	ActOp41(dPerson* _ppl_vec, dCommunity* _comm_vec, unsigned int* _nNumWantVaccine,int _nAscertainmentDelay){
		ppl_vec = _ppl_vec;
		comm_vec = _comm_vec;
		nNumWantVaccine = _nNumWantVaccine;
		nAscertainmentDelay = _nAscertainmentDelay;
	}
	
	__device__
	void operator()(dTract& t){

		if (!dTract::isVaccinated(t)) {
			int nNumAscertained=0; // number of people ascertained in this tract
			for (unsigned int i=t.nFirstCommunity; i<t.nLastCommunity; i++)
				for (int j=0; j<TAG; j++)
					nNumAscertained += comm_vec[i].nEverAscertained[j];
			if (nNumAscertained>0) { // case found in tract
				VaccinateOp vacc_obj(ppl_vec, comm_vec,nNumWantVaccine,nAscertainmentDelay);
				vacc_obj.vaccinate(t);
			}
		}
	}
};

struct ActOp42{
	dPerson* ppl_vec;
	dCommunity* comm_vec;
	int nAscertainmentDelay;
	
	ActOp42(dPerson* _ppl_vec, dCommunity* _comm_vec, int _nAscertainmentDelay){
		ppl_vec = _ppl_vec;
		comm_vec = _comm_vec;
		nAscertainmentDelay = _nAscertainmentDelay;
	}
	
	__device__ 
	void operator()(dTract& t){
		int nNumAscertained=0; // number of children ascertained in this tract
		for (unsigned int i=t.nFirstCommunity; i<t.nLastCommunity; i++)
			nNumAscertained += comm_vec[i].nEverAscertained[0]+comm_vec[i].nEverAscertained[1];
		
		if (nNumAscertained>0 && 
			(!dTract::isSchoolClosed(t,1) || !dTract::isSchoolClosed(t,2) ||
			!dTract::isSchoolClosed(t,3) || !dTract::isSchoolClosed(t,4) ||
			!dTract::isSchoolClosed(t,5) || !dTract::isSchoolClosed(t,6) ||
			!dTract::isSchoolClosed(t,7) || !dTract::isSchoolClosed(t,8))) { // close schools in this tract
	    
			for (unsigned int i=t.nFirstCommunity; i<t.nLastCommunity; i++) {
				for (unsigned int pid=comm_vec[t.nFirstCommunity].nFirstPerson;
				pid<comm_vec[t.nLastCommunity-1].nLastPerson;pid++) {
			
					if (dPerson::isChild(ppl_vec[pid]) && ppl_vec[pid].nWorkplace>0 && 
					ppl_vec[pid].nWorkplace<9 && isAscertained(ppl_vec[pid],nAscertainmentDelay) && 
					!dTract::isSchoolClosed(t,ppl_vec[pid].nWorkplace)) {
				
						dTract::setSchoolClosed(t,ppl_vec[pid].nWorkplace);
					}
				}
			}
		}
	}
};

struct ActOp43{
	int nTimer;
	
	ActOp43(int _nTimer){nTimer = _nTimer;}

	__device__ 
	void operator()(dTract& t){
		if (dTract::isSchoolClosed(t,1) &&                       // school is closed
		--t.nSchoolClosureTimer<=0 &&                // school closure is not in effect anymore
	    dnSchoolOpeningDays[t.fips_state-1]-1<=nTimer/2) { // school should be open
	  
			for (int i=0; i<9; i++)
				dTract::setSchoolOpen(t,i);// school is open again
		}
	}
};

struct ActOp61{
	unsigned int* wantthisvac;
	int vacnum;
	
	ActOp61(unsigned int* _wantthisvac, int _vacnum){
		wantthisvac = _wantthisvac;
		vacnum = _vacnum;
	}
	
	__device__ 
	void operator()(dPerson& p){
		if (p.bWantVac && p.bVaccineEligible[vacnum] &&
	    (!dPerson::isVaccinated(p) || (dPerson::whichVaccine(p)==vacnum &&
	    ((dVaccineData[vacnum].nNumDoses>1 &&
		p.vday>=dVaccineData[vacnum].nBoostDay) ||
	    (dPerson::needsBoost(p) && p.vday>=ddefaultboostday)))))
			atomicAdd(&(wantthisvac[p.nVaccinePriority]),1);
	}
};

struct ActOp62{
	int priority;
	int vacnum;
	double vFrac;
	
	RandGen* rand_vec;
	
	unsigned int* nNumVaccineDosesUsed;
	unsigned int* nVacLim_vec;
	
	unsigned int* nNumWantVaccine; 
	
	prevaccType ePrevaccinationStrategy;
	
	int* mutex;
	
	ActOp62(int _priority, int _vacnum, double _vFrac,RandGen* _rand_vec,
		unsigned int* _nNumVaccineDosesUsed,unsigned int* _nVacLim_vec,unsigned int* _nNumWantVaccine,
		prevaccType _ePrevaccinationStrategy, int* _mutex
		){
		
		priority = _priority;
		vacnum = _vacnum;
		vFrac = _vFrac;
		rand_vec = _rand_vec;
	
		nNumVaccineDosesUsed = _nNumVaccineDosesUsed;
		nNumWantVaccine = _nNumWantVaccine;
		nVacLim_vec = _nVacLim_vec;
		
		ePrevaccinationStrategy = _ePrevaccinationStrategy;
		mutex = _mutex;
	}
	

	__device__
	void operator()(dPerson& p){
		RandGen& rand_obj = rand_vec[p.id];
	
		if (p.bWantVac && dPerson::getVaccinePriority(p)==priority && p.bVaccineEligible[vacnum] &&
		(!dPerson::isVaccinated(p) ||
		(dPerson::whichVaccine(p)==vacnum &&
		(p.vday>=dVaccineData[vacnum].nBoostDay ||
		(dPerson::needsBoost(p) && p.vday>=ddefaultboostday))))) {
			if (vFrac>=1.0 || rand_obj.cudaRandUni() < vFrac) {
				if (dPerson::needsBoost(p) && dVaccineData[vacnum].nNumDoses>1)
					dPerson::clearNeedsBoost(p);
			
				atomicAdd(&(nNumVaccineDosesUsed[vacnum]),1);
				
				nVacLim_vec[p.id] = 1;
				
				dPerson::setWhichVaccine(p, vacnum);
		
				if (!dPerson::isVaccinated(p)) {
					dPerson::setVaccinated(p);
					p.vday = 0;
					if (dVaccineData[vacnum].nNumDoses<=1 && !dPerson::needsBoost(p)) {
						p.bWantVac = false;
						dPerson::setBoosted(p);
						atomicSub(&(nNumWantVaccine[0]),1);
					} else if (ePrevaccinationStrategy==PRIMEBOOSTRANDOM) {
						atomicSub(&(nNumWantVaccine[0]),1);
						p.bWantVac = false; // only gets one shot if PRIMEBOOSTRANDOM
					}
				} else {
					p.bWantVac = false;
					dPerson::setBoosted(p);
					atomicSub(&(nNumWantVaccine[0]),1);
				}
			}
	    }
	}
};

struct ActOp71{
	unsigned int* nNumAntiviralsUsed;
	unsigned int* nNumWantAV;
	
	unsigned int uAVFraction;
	
	RandGen* rand_vec;
	
	ActOp71(unsigned int* _nNumAntiviralsUsed, unsigned int* _nNumWantAV,
		unsigned int _uAVFraction, RandGen* _rand_vec){
		
		nNumAntiviralsUsed = _nNumAntiviralsUsed;
		nNumWantAV = _nNumWantAV;
		
		uAVFraction = _uAVFraction;
		rand_vec = _rand_vec;
	}
	
	__device__
	void operator()(dPerson& p){
		RandGen& rand_obj = rand_vec[p.id];
	
		if (p.bWantAV && (uAVFraction==UINT_MAX || rand_obj.cudaRandInt()<uAVFraction)) {
			p.bWantAV = false;
			dPerson::setAntiviral(p);

			p.nAVTimer = dnAntiviralCourseSize;  // supply course of AV to this person
			atomicAdd(&(nNumAntiviralsUsed[0]),1);
			atomicSub(&(nNumWantAV[0]),1);
		}
	}
};

/****************** stats ***************/
void cudaStats();

struct StatsOp1{
	__device__
	unsigned int operator()(dCommunity& t){
		unsigned int nNumSymptomatic = 0;
		for(int j=0; j<TAG; j++){
			nNumSymptomatic += t.nsym[j];
		}
		return nNumSymptomatic;
	}
};

struct StatsOp2{
	__device__
	unsigned int operator()(dCommunity& t){
		unsigned int nNumCumulativeSymptomatic = 0;
		for(int j=0; j<TAG; j++){
			nNumCumulativeSymptomatic += t.nEverSymptomatic[j];
		}
		return nNumCumulativeSymptomatic;
	}
};

typedef thrust::device_vector<dPerson> dPersonVec;
typedef thrust::device_vector<dCommunity> dCommunityVec;
typedef thrust::device_vector<dCommWorker> dCommWorkerVec;
typedef thrust::device_vector<dCommVisitor> dCommVisitorVec;
typedef thrust::device_vector<dTract> dTractVec;

typedef thrust::host_vector<dPerson> hPersonVec;
typedef thrust::host_vector<dCommunity> hCommunityVec;
typedef thrust::host_vector<dCommWorker> hCommWorkerVec;
typedef thrust::host_vector<dCommVisitor> hCommVisitorVec;
typedef thrust::host_vector<dTract> hTractVec;

typedef thrust::device_vector<unsigned int> dIdxVec;

typedef thrust::device_vector<RandGen> dRandVec;
typedef thrust::host_vector<RandGen> hRandVec;



#endif
